package yxy.cherry.chat.message;

import java.util.HashMap;
import java.util.Set;

import com.google.protobuf.ByteString;
import com.google.protobuf.MessageLite;
import com.google.protobuf.Parser;

import yxy.apple.logger.Logger;
import yxy.apple.util.ReflectionUtility;
import yxy.cherry.game.base.message.annotation.MessageSource;
import yxy.cherry.game.base.message.annotation.MessageType;
import yxy.cherry.game.base.module.IGameModule;
import yxy.game.pm2.command.Command;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class MessageDispatcher {
	protected static Logger logger = Logger.create(MessageDispatcher.class);

	static private MessageDispatcher instance;

	static public MessageDispatcher getInstance() {
		if (instance == null) {
			instance = new MessageDispatcher();
		}
		return instance;
	}

	private MessageDispatcher() {
	}

	private HashMap<Integer, Command> commands = new HashMap<>();

	public void initMessage(IGameModule module) throws Exception {
		Set<Class<?>> messageTypes = ReflectionUtility.getTypesAnnotatedWith(module.commandPackage(), MessageType.class);
		for (Class<?> clazz : messageTypes) {
			int proto = clazz.getAnnotation(MessageType.class).proto();
			Class<? extends MessageLite> cls = clazz.getAnnotation(MessageType.class).classtype();
			Parser<? extends MessageLite> parser = (Parser) cls.getDeclaredMethod("parser").invoke(null);
			Command clazzObj = (Command) clazz.getConstructor().newInstance();
			commands.put(proto, clazzObj);
			logger.info("[0x%08x]%s:%s -> %s", proto, clazz.getSimpleName(), cls.getSimpleName(), parser.toString());
		}
		module.setMessageEmitter(MessageEmitter.getInstance());
	}

	public void handleMessage(int sequence, MessageSource messageSource, int proto, ByteString data) {
		try {
			Command command = commands.get(proto);
			Class<? extends MessageLite> cls = command.getClass().getAnnotation(MessageType.class).classtype();
			Parser<? extends MessageLite> parser = (Parser) cls.getDeclaredMethod("parser").invoke(null);
			logger.info("command parser::>>>>>>::[0x%08x]   %s", proto, command.getClass().getName());
			command.clone().execute(messageSource, parser.parseFrom(data));
		} catch (Exception e) {
			logger.error("处理消息时发生异常 - %s, proto: %d", messageSource, proto);
			logger.error(e);
		}
	}
}
